# -*- encoding:utf8 -*-
from attendance.models import *
from datetime import timedelta, datetime, date
# from leave_accum import get_avai_annual
from attendance.convert import str2date, td2i, date2str, t2i, i2t, dt2str,td2i,day2i
from attendance.tool_func import get_or_none
from django.db.models.signals import pre_delete
from django.dispatch import receiver
from django.db.models import F


def match(staff):
    """
    匹配一个员工的所有(未匹配的)调休，年假
    """
    for leave in LeaveModel.objects.filter(category__in=['annual_leave','swap_off','annual_leave_import','swap_off_import'],
                                           staff=staff, matched=False).order_by('start_time'):
        __match(leave)
            #_match_a_leave(leave)
        #elif leave.category in ['annual_leave_import','swap_off_import']:
            #_match_a_import_leave(leave)

            
# def _match_a_leave(leave):
    # """
    # 将一个LeaveModel（请假）与Availeave（可用）假期匹配起来，
    # 匹配结果（关系）记录在ConsumeRelation数据表中
    # """
    
    # need=leave.span()-reduce(lambda x,y:x+y.span(), leave.relation.all(),0)
    # pos=str2dt(leave.start_time)
    # end=str2dt(leave.end_time)
    # for avai in AvaiLeave.objects.filter(staff=leave.staff,used__lt=F('span'),category=leave.category,\
                                         # is_valid=True,span__gt=i2t(0)).order_by('start_date'):
        # avai_used=t2i(avai.used)
        # avai_left=t2i(avai.span)-avai_used
        # if avai_left==0:
            # continue
        # elif avai_left>=need:
            # r,created=ConsumeRelation.objects.get_or_create(avai_leave=avai,used_leave=leave)
            # if created:
                # r.avai_leave_start=i2t(avai_used)
                # r.used_leave_start=dt2str(pos)
            # r.avai_leave_end=i2t(avai_used+need)
            # r.used_leave_end=leave.end_time
            # r.save()
            # #ConsumeRelation(avai_leave=avai,avai_leave_start=i2t(avai_used), avai_leave_end=i2t(avai_used+need),
                            # #used_leave=leave, used_leave_start=dt2str(pos),
                            # #used_leave_end=leave.end_time).save()
            # avai.used=i2t(avai_used+need)
            # avai.save()
            # leave.matched=True
            # leave.save()
            # return True
        # else: # 不够的情况
            # used_leave_end= pos+timedelta(minutes=avai_left)
            # r,created=ConsumeRelation.objects.get_or_create(avai_leave=avai,used_leave=leave)
            # if created:
                # r.avai_leave_start=avai.used
                # r.used_leave_start=dt2str(pos)
            # r.avai_leave_end=avai.span
            # r.used_leave_end=dt2str(used_leave_end)
            # r.save()            
            # #ConsumeRelation(avai_leave=avai,avai_leave_start=avai.used, avai_leave_end=avai.span,
                            # #used_leave=leave, used_leave_start=dt2str(pos),
                            # #used_leave_end=dt2str(used_leave_end)).save()
            # pos=used_leave_end
            # need=td2i(end-pos)
            # avai.used=avai.span
            # avai.save()    
    # raise LeaveNotEnough('not enough leave') 
 

def __match(leave):
    leave_app=factory(leave)
    for avai in get_next_avai_leave(leave_app.staff, leave.category):
        if avai.longer(leave_app):
            avai.hold(leave_app)
            break
        else:
            leave_app.consume(avai)

def get_next_avai_leave(staff,category):
    if category in ['annual_leave_import','swap_off_import']:
        category=category.rstrip('_import')   
    for avai in AvaiLeave.objects.filter(staff=staff,used__lt=F('span'),category=category,\
                                            is_valid=True,span__gt=i2t(0)).order_by('start_date'):

        wraper=AvaiWraper(avai)
        if wraper.left()==0:
            continue   
        else:
            yield wraper

def factory(leave):
    if leave.category in ['annual_leave','swap_off']:
        return RealAppWraper(leave)
    elif leave.category in ['annual_leave_import','swap_off_import']:
        return ImportAppWraper(leave)
    else:
        raise UserWarning,'leave category is %s ,not need match'%leave.category

def dtstr_add_minites(dtstr,minutes):
    return dt2str( str2dt(dtstr)+ timedelta(minutes=minutes) ) 

class Wraper(object):
    def __init__(self,model_obj):
        self.model=model_obj
        
    def __getattr__(self,name):
        return getattr(self.model,name)
    
    def longer(self,other):
        return self.left()>other.left()
    
class AvaiWraper(Wraper):
    def left(self):
        return self.model.left() 
    def span(self):
        return t2i(self.model.span)
    
    def consumed(self):
        return t2i(self.model.used)
    
    def hold(self,leave_app):
        r,created=ConsumeRelation.objects.get_or_create(avai_leave=self.model,used_leave=leave_app.model)
        if created:
            r.avai_leave_start=i2t(self.consumed())
            r.used_leave_start=dtstr_add_minites(leave_app.start_time,leave_app.holded())
        r.avai_leave_end=i2t(self.consumed()+leave_app.left())
        r.used_leave_end=leave_app.end_time
        r.save()
        
        self.add_cusumed(leave_app.left())
        leave_app.add_holded(leave_app.left())
        

    def add_cusumed(self,span):
        self.model.used= i2t(self.consumed()+span)
        self.model.save()

class AppWraper(Wraper): 
    def left(self):
        return self.span()-self._holded
    
    def consume(self,avai):
        r,created=ConsumeRelation.objects.get_or_create(avai_leave=avai.model,used_leave=self.model)
        if created:
            r.avai_leave_start=i2t(avai.consumed())
            r.used_leave_start=self.add_minites(self.holded())
        r.avai_leave_end=i2t(avai.consumed()+avai.left())
        r.used_leave_end=self.add_minites(self.holded()+avai.left())
        r.save() 
        self.add_holded(avai.left())
        avai.add_cusumed(avai.left())
        
    def holded(self):
        return self._holded
    def add_minites(self,minite):
        return dtstr_add_minites(self.start_time,minite)
    def add_holded(self,span):
        self._holded+=span
        if self._holded==self.model.span():
            self.model.matched=True
            self.model.save()

class RealAppWraper(AppWraper):
    def __init__(self, application):
        AppWraper.__init__(self,application)
        self._holded=reduce(lambda x,y:x+y.span(), application.relation.all(),0)
        
class ImportAppWraper(AppWraper):
    def __init__(self, application):
        AppWraper.__init__(self,application)
        # TODO，如何度量 导入假期的长度
        # 导入方式 替换为 其他，这里暂时不管了。 2016/2/25
        # self._holded=t2i(application.note)